package com.uinnova.product.eam.service.impl;

import com.alibaba.fastjson.JSON;
import com.binary.core.util.BinaryUtils;
import com.binary.framework.exception.ServiceException;
import com.binary.jdbc.Page;
import com.uinnova.product.eam.base.util.ExcelUtil;
import com.uinnova.product.eam.comm.model.es.AppSquareConfig;
import com.uinnova.product.eam.model.vo.*;
import com.uinnova.product.eam.service.AppSquareConfigSvc;
import com.uinnova.product.eam.service.ICISwitchSvc;
import com.uinnova.product.eam.service.ThematicAnalysisSvc;
import com.uinnova.product.vmdb.comm.model.ci.CcCi;
import com.uinnova.product.vmdb.comm.model.ci.CcCiAttrDef;
import com.uinnova.product.vmdb.comm.model.ci.CcCiClass;
import com.uinnova.product.vmdb.comm.model.rlt.CcCiRlt;
import com.uinnova.product.vmdb.comm.util.CommUtil;
import com.uinnova.product.vmdb.provider.ci.bean.CcCiClassInfo;
import com.uino.api.client.cmdb.IRltClassApiSvc;
import com.uino.bean.cmdb.base.*;
import com.uino.bean.cmdb.query.ESRltSearchBean;
import com.uino.dao.BaseConst;
import com.uino.dao.cmdb.ESCIClassSvc;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.File;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 专题分析相关接口实现
 * @author ch
 */
@Service
@Slf4j
public class ThematicAnalysisSvcImpl implements ThematicAnalysisSvc {

    @Resource
    private AppSquareConfigSvc configSvc;
    @Resource
    private ESCIClassSvc ciClassSvc;
    @Resource
    private ICISwitchSvc ciSwitchSvc;
    @Autowired
    private IRltClassApiSvc rltClassApiSvc;
    @Resource
    private IamsCIRltSwitchSvc rltSwitchSvc;

    private static final String STR_NUM = "序号";
    private static final String MESSAGE = "配置信息已过时,请更新矩阵分析配置!";

    @Override
    public EamMatrixAnalysisVo getMatrixById(Long id) {
        AppSquareConfig configInfo = configSvc.getInfoById(id);
        EamMatrixAnalysisVo result = new EamMatrixAnalysisVo();

        MatrixAnalysisConfigVo config = JSON.parseObject(configInfo.getConfigure(), MatrixAnalysisConfigVo.class);
        result.setMatrixType(config.getMatrixType());
        ESCIClassInfo rowClass = ciClassSvc.getById(config.getRowClassId());
        if(rowClass == null){
            throw new ServiceException(MESSAGE);
        }
        if(config.getMatrixType().equals(1)){
            ESCIClassInfo colClass = ciClassSvc.getById(config.getColClassId());
            CcCiClassInfo rltClass = rltClassApiSvc.getRltClassById(config.getRltClassId());
            if(colClass == null || rltClass == null){
                throw new ServiceException(MESSAGE);
            }
            result.setRowId(rowClass.getId());
            result.setRowName(rowClass.getClassName());
            result.setColId(colClass.getId());
            result.setColName(colClass.getClassName());
            this.getRltMatrix(result, rowClass, colClass, rltClass.getCiClass());
        }else{
            Map<Long, ESCIAttrDefInfo> attrDefMap = rowClass.getAttrDefs().stream().collect(Collectors.toMap(CcCiAttrDef::getId, e -> e, (k1, k2) -> k2));
            ESCIAttrDefInfo rowAttrDef = attrDefMap.get(config.getRowAttrId());
            ESCIAttrDefInfo colAttrDef = attrDefMap.get(config.getColAttrId());
            if(rowAttrDef == null || colAttrDef == null){
                throw new ServiceException(MESSAGE);
            }
            result.setRowName(rowAttrDef.getProName());
            result.setColName(colAttrDef.getProName());
            this.getAttrMatrix(result, rowClass, rowAttrDef, colAttrDef);
        }
        return result;
    }

    /**
     * 通过关系获取矩阵分析数据
     * @param matrixAnalysis 矩阵分析
     * @param rowClass 横向分类
     * @param colClass 纵向分类
     * @param rltClass 关系分类
     */
    private void getRltMatrix(EamMatrixAnalysisVo matrixAnalysis, ESCIClassInfo rowClass, ESCIClassInfo colClass, CcCiClass rltClass) {
        List<ESCIInfo> rowCiList = ciSwitchSvc.getCiByClassIds(Collections.singletonList(rowClass.getId()), null, LibType.DESIGN);
        List<ESCIInfo> colCiList = ciSwitchSvc.getCiByClassIds(Collections.singletonList(colClass.getId()), null, LibType.DESIGN);

        for (ESCIInfo each : rowCiList) {
            String name = each.getCiLabel().replaceAll("[\\[\\]\\\\\"]", "");
            CiSimpleInfoVo ciVo = new CiSimpleInfoVo(each.getId(), name, each.getCiCode(), rowClass.getId(), rowClass.getClassName());
            matrixAnalysis.getRowTitleList().add(ciVo);
        }
        for (ESCIInfo each : colCiList) {
            String name = each.getCiLabel().replaceAll("[\\[\\]\\\\\"]", "");
            CiSimpleInfoVo ciVo = new CiSimpleInfoVo(each.getId(), name, each.getCiCode(), colClass.getId(), colClass.getClassName());
            matrixAnalysis.getColTitleList().add(ciVo);
        }
        Long rltClassId = rltClass.getId();
        List<ESCIRltInfo> rltRowInfo = this.getRltInfo(rltClassId, rowClass.getId(), colClass.getId());
        List<ESCIRltInfo> rltColInfo = this.getRltInfo(rltClassId, colClass.getId(), rowClass.getId());
        List<ESCIRltInfo> rltData = new ArrayList<>(rltRowInfo);
        rltData.addAll(rltColInfo);
        Map<String, ESCIRltInfo> rltMap = rltData.stream().collect(Collectors.toMap(CcCiRlt::getCiCode, e -> e, (k1, k2) -> k2));
        List<List<RltSimpleInfoVo>> rltMatrix = new ArrayList<>();
        for (ESCIInfo colCi : colCiList) {
            List<RltSimpleInfoVo> rowRltList = new ArrayList<>();
            for (ESCIInfo rowCi : rowCiList) {
                RltSimpleInfoVo rltVo = new RltSimpleInfoVo(rowCi.getCiCode(), colCi.getCiCode());
                rltVo.setSourceCiName(rowCi.getCiLabel().replaceAll("[\\[\\]\\\\\"]", ""));
                rltVo.setTargetCiName(colCi.getCiLabel().replaceAll("[\\[\\]\\\\\"]", ""));
                String rltColCode = colCi.getCiCode() + "_" + rltClassId + "_" + rowCi.getCiCode();
                ESCIRltInfo rltInfo = rltMap.get(rltColCode);
                if(rltInfo == null){
                    String rltRowCode = rowCi.getCiCode() + "_" + rltClassId + "_" + colCi.getCiCode();
                    rltInfo = rltMap.get(rltRowCode);
                }
                if(rltInfo != null){
                    rltVo.setInclude(true);
                    rltVo.setId(rltInfo.getId());
                    rltVo.setCiCode(rltInfo.getCiCode());
                    rltVo.setUniqueCode(rltInfo.getUniqueCode());
                }
                rowRltList.add(rltVo);
            }
            rltMatrix.add(rowRltList);
        }
        matrixAnalysis.setRltMatrix(rltMatrix);
    }

    /**
     * 通过属性获取矩阵分析数据
     * @param matrixAnalysis 矩阵数据
     * @param classInfo 分类信息
     * @param rowAttrDef 横向属性
     * @param colAttrDef 纵向属性
     */
    private void getAttrMatrix(EamMatrixAnalysisVo matrixAnalysis, ESCIClassInfo classInfo, ESCIAttrDefInfo rowAttrDef, ESCIAttrDefInfo colAttrDef) {
        List<ESCIInfo> ciList = ciSwitchSvc.getCiByClassIds(Collections.singletonList(classInfo.getId()), null, LibType.DESIGN);
        Set<String> rowList = new LinkedHashSet<>();

        Map<String, List<ESCIInfo>> attrColGroup = new LinkedHashMap<>();
        for (ESCIInfo each : ciList) {
            Map<String, Object> attrs = each.getAttrs();
            if(CollectionUtils.isEmpty(attrs)){
                continue;
            }
            Object rowAttr = attrs.get(rowAttrDef.getProStdName());
            Object colAttr = attrs.get(colAttrDef.getProStdName());
            if(rowAttr != null){
                rowList.add(rowAttr.toString());
            }
            if(colAttr != null){
                attrColGroup.computeIfAbsent(colAttr.toString(), key -> new ArrayList<>()).add(each);
            }
        }
        for (String each : rowList) {
            CiSimpleInfoVo ciVo = new CiSimpleInfoVo(each, rowAttrDef.getId(), rowAttrDef.getProName());
            matrixAnalysis.getRowTitleList().add(ciVo);
        }
        for (Map.Entry<String, List<ESCIInfo>> entry : attrColGroup.entrySet()) {
            CiSimpleInfoVo ciVo = new CiSimpleInfoVo(entry.getKey(), colAttrDef.getId(), colAttrDef.getProName());
            matrixAnalysis.getColTitleList().add(ciVo);
        }
        List<List<List<CiSimpleInfoVo>>> attrMatrix = new ArrayList<>();
        for (Map.Entry<String, List<ESCIInfo>> entry : attrColGroup.entrySet()) {
            List<List<CiSimpleInfoVo>> rowCiList = new ArrayList<>();
            List<ESCIInfo> colCiList = entry.getValue();
            Map<String, List<ESCIInfo>> attrRowGroup = new HashMap<>();
            for (ESCIInfo colCi : colCiList) {
                Map<String, Object> attrs = colCi.getAttrs();
                if(CollectionUtils.isEmpty(attrs)){
                    continue;
                }
                Object rowAttr = attrs.get(rowAttrDef.getProStdName());
                if(rowAttr != null){
                    attrRowGroup.computeIfAbsent(rowAttr.toString(), key -> new ArrayList<>()).add(colCi);
                }
            }
            for (String row : rowList) {
                List<CiSimpleInfoVo> paneCiList = new ArrayList<>();
                for (ESCIInfo each : attrRowGroup.getOrDefault(row, new ArrayList<>())) {
                    String name = each.getCiLabel().replaceAll("[\\[\\]\\\\\"]", "");
                    CiSimpleInfoVo paneCi = new CiSimpleInfoVo(each.getId(), name, each.getCiCode(), each.getClassId(), classInfo.getClassName());
                    paneCiList.add(paneCi);
                }
                rowCiList.add(paneCiList);
            }
            attrMatrix.add(rowCiList);
        }
        matrixAnalysis.setAttrMatrix(attrMatrix);
    }

    private List<ESCIRltInfo> getRltInfo(Long rltClassId, Long sourceClassId, Long targetClassId){
        ESRltSearchBean bean = new ESRltSearchBean();
        bean.setPageSize(1);
        bean.setPageSize(10000);
        bean.setDomainId(BaseConst.DEFAULT_DOMAIN_ID);
        bean.setSourceClassIds(Collections.singletonList(sourceClassId));
        bean.setTargetClassIds(Collections.singletonList(targetClassId));
        bean.setRltClassIds(Collections.singletonList(rltClassId));
        Page<ESCIRltInfo> rltInfoPage = rltSwitchSvc.searchRlt(bean, LibType.DESIGN);
        return CollectionUtils.isEmpty(rltInfoPage.getData())?Collections.emptyList():rltInfoPage.getData();
    }

    @Override
    public List<EamMatrixTableVo> getMatrixTable(Long id) {
        AppSquareConfig configInfo = configSvc.getInfoById(id);
        List<EamMatrixTableVo> result = new ArrayList<>();
        MatrixAnalysisConfigVo config = JSON.parseObject(configInfo.getConfigure(), MatrixAnalysisConfigVo.class);

        ESCIClassInfo rowClass = ciClassSvc.getById(config.getRowClassId());
        if(rowClass == null){
            throw new ServiceException(MESSAGE);
        }
        if(config.getMatrixType().equals(1)){
            ESCIClassInfo colClass = ciClassSvc.getById(config.getColClassId());
            CcCiClassInfo rltClass = rltClassApiSvc.getRltClassById(config.getRltClassId());
            if(colClass == null || rltClass == null){
                throw new ServiceException(MESSAGE);
            }
            this.getRltMatrixTable(result, rowClass, colClass, rltClass.getCiClass());
        }else{
            Map<Long, ESCIAttrDefInfo> attrDefMap = rowClass.getAttrDefs().stream().collect(Collectors.toMap(CcCiAttrDef::getId, e -> e, (k1, k2) -> k2));
            ESCIAttrDefInfo rowAttrDef = attrDefMap.get(config.getRowAttrId());
            ESCIAttrDefInfo colAttrDef = attrDefMap.get(config.getColAttrId());
            if(rowAttrDef == null || colAttrDef == null){
                throw new ServiceException(MESSAGE);
            }
            this.getAttrMatrixTable(result, rowClass, rowAttrDef, colAttrDef);
        }
        return result;
    }

    /**
     * 通过关系获取矩阵表格数据
     * @param tableList 矩阵分析
     * @param rowClass 横向分类
     * @param colClass 纵向分类
     * @param rltClass 关系分类
     */
    private void getRltMatrixTable(List<EamMatrixTableVo> tableList, ESCIClassInfo rowClass, ESCIClassInfo colClass, CcCiClass rltClass) {
        //组装header
        List<EamCiTableVo> headers = this.getRltMatrixTableHeader(rowClass, colClass);
        Long rltClassId = rltClass.getId();
        List<ESCIRltInfo> rltRowInfo = this.getRltInfo(rltClassId, rowClass.getId(), colClass.getId());
        List<ESCIRltInfo> rltColInfo = this.getRltInfo(rltClassId, colClass.getId(), rowClass.getId());
        if(CollectionUtils.isEmpty(rltRowInfo) && CollectionUtils.isEmpty(rltColInfo)){
            return;
        }
        Map<String, List<ESCIRltInfo>> sourceGroup = new HashMap<>();
        Map<String, List<ESCIRltInfo>> targetGroup = new HashMap<>();
        List<String> rowCiCodes = new ArrayList<>();
        List<String> colCiCodes = new ArrayList<>();
        for (ESCIRltInfo each : rltRowInfo) {
            rowCiCodes.add(each.getSourceCiCode());
            colCiCodes.add(each.getTargetCiCode());
            sourceGroup.computeIfAbsent(each.getSourceCiCode(), key -> new ArrayList<>()).add(each);
            targetGroup.computeIfAbsent(each.getTargetCiCode(), key -> new ArrayList<>()).add(each);
        }
        for (ESCIRltInfo each : rltColInfo) {
            rowCiCodes.add(each.getTargetCiCode());
            colCiCodes.add(each.getSourceCiCode());
            sourceGroup.computeIfAbsent(each.getSourceCiCode(), key -> new ArrayList<>()).add(each);
            targetGroup.computeIfAbsent(each.getTargetCiCode(), key -> new ArrayList<>()).add(each);
        }
        List<ESCIInfo> rowCiList = ciSwitchSvc.getCiByCodes(rowCiCodes, null, LibType.DESIGN);
        List<ESCIInfo> colCiList = ciSwitchSvc.getCiByCodes(colCiCodes, null, LibType.DESIGN);
        Map<String, ESCIInfo> ciMap = colCiList.stream().collect(Collectors.toMap(CcCi::getCiCode, e -> e, (k1, k2) -> k2));
        for (ESCIInfo ci : rowCiList) {
            List<ESCIRltInfo> sourceRltList = sourceGroup.getOrDefault(ci.getCiCode(), new ArrayList<>());
            List<ESCIRltInfo> targetRltList = targetGroup.getOrDefault(ci.getCiCode(), new ArrayList<>());
            if(CollectionUtils.isEmpty(sourceRltList) && CollectionUtils.isEmpty(targetRltList)){
                continue;
            }
            String label = ci.getCiLabel().replaceAll("[\\[\\]\\\\\"]", "");
            EamMatrixTableVo tableVo = new EamMatrixTableVo(1, label, rowClass.getClassName(), headers);
            this.getRltMatrixTableData(sourceRltList, tableVo, ci, ciMap, headers, true);
            this.getRltMatrixTableData(targetRltList, tableVo, ci, ciMap, headers, false);
            tableList.add(tableVo);
        }
    }

    /**
     * 获取矩阵表格表头
     * @param rowClass 横向分类
     * @param colClass 纵向分类
     * @return 表头
     */
    private List<EamCiTableVo> getRltMatrixTableHeader(ESCIClassInfo rowClass, ESCIClassInfo colClass){
        List<EamCiTableVo> result = new ArrayList<>();
        for (ESCIAttrDefInfo attrDef : rowClass.getAttrDefs()) {
            //取出label字段
            if(attrDef.getIsCiDisp().equals(1)){
                String attrName = attrDef.getProName() + ",[" + rowClass.getClassName() + "]";
                result.add(new EamCiTableVo(attrDef.getProStdName(), attrName, rowClass.getId(), rowClass.getClassName(), true));
            }
        }
        for (ESCIAttrDefInfo attrDef : colClass.getAttrDefs()) {
            if(attrDef.getIsCiDisp().equals(1)){
                String attrName = attrDef.getProName() + ",[" + colClass.getClassName() + "]";
                result.add(new EamCiTableVo(attrDef.getProStdName(), attrName, colClass.getId(), colClass.getClassName(), false));
            }
        }
        return result;
    }

    /**
     * 获取关系矩阵表格数据
     * @param rltList 关系集合
     * @param tableVo 表数据
     * @param rowCi 横向ci
     * @param ciMap ciMap
     * @param headers 表头
     * @param direction 方向
     */
    private void getRltMatrixTableData(List<ESCIRltInfo> rltList, EamMatrixTableVo tableVo, ESCIInfo rowCi, Map<String, ESCIInfo> ciMap, List<EamCiTableVo> headers, boolean direction){
        for (ESCIRltInfo rltInfo : rltList) {
            Map<String, Object> data = new HashMap<>();
            ESCIInfo colCi = direction?ciMap.get(rltInfo.getTargetCiCode()):ciMap.get(rltInfo.getSourceCiCode());
            if(colCi == null){
                continue;
            }
            for (EamCiTableVo header : headers) {
                Object value;
                if(rowCi.getClassId().equals(header.getClassId())){
                    value = rowCi.getAttrs().get(header.getProName());
                }else{
                    value = colCi.getAttrs().get(header.getProName());
                }
                data.put(header.getAttrKey(), value);
                if(header.getMerge()){
                    tableVo.getCountMap().computeIfAbsent(value.toString(), k->new AtomicInteger(0)).incrementAndGet();
                }
            }
            tableVo.getData().add(data);
        }
    }

    /**
     * 获取属性矩阵表
     * @param tableList 表格数据
     * @param classInfo 分类
     * @param rowAttrDef 横向属性
     * @param colAttrDef 纵向属性
     */
    private void getAttrMatrixTable(List<EamMatrixTableVo> tableList, ESCIClassInfo classInfo, ESCIAttrDefInfo rowAttrDef, ESCIAttrDefInfo colAttrDef) {
        List<ESCIInfo> ciList = ciSwitchSvc.getCiByClassIds(Collections.singletonList(classInfo.getId()), null, LibType.DESIGN);
        Map<String, List<ESCIInfo>> attrRowGroup = this.groupCiByAttr(ciList, rowAttrDef.getProStdName());
        //组装header
        List<EamCiTableVo> headers = this.getAttrMatrixTableHeader(classInfo, rowAttrDef, colAttrDef);
        for (Map.Entry<String, List<ESCIInfo>> entry : attrRowGroup.entrySet()) {
            EamMatrixTableVo tableVo = new EamMatrixTableVo(2, rowAttrDef.getProStdName(), classInfo.getClassName(), headers);
            tableVo.setAttrName(entry.getKey());
            Map<String, List<ESCIInfo>> colCiGroup = this.groupCiByAttr(entry.getValue(), colAttrDef.getProStdName());
            for (Map.Entry<String, List<ESCIInfo>> colEntry : colCiGroup.entrySet()) {
                for (ESCIInfo ciInfo : colEntry.getValue()) {
                    Map<String, Object> data = new HashMap<>();
                    for (EamCiTableVo header : headers) {
                        Object value = ciInfo.getAttrs().get(header.getProName());
                        data.put(header.getAttrKey(), value);
                        if(header.getProName().equals(colAttrDef.getProStdName())){
                            tableVo.getCountMap().computeIfAbsent(value.toString(), k->new AtomicInteger(0)).incrementAndGet();
                        }
                    }
                    tableVo.getData().add(data);
                }
            }
            if(CollectionUtils.isEmpty(tableVo.getData())){
                continue;
            }
            tableVo.getCountMap().put(entry.getKey(), new AtomicInteger(tableVo.getData().size()));
            tableList.add(tableVo);
        }
    }

    /**
     * 按属性值分组
     * @param ciList ci集合
     * @param name 属性名
     * @return 分组
     */
    private Map<String, List<ESCIInfo>> groupCiByAttr(List<ESCIInfo> ciList, String name){
        Map<String, List<ESCIInfo>> result = new HashMap<>();
        for (ESCIInfo each : ciList) {
            Map<String, Object> attrs = each.getAttrs();
            if(CollectionUtils.isEmpty(attrs)){
                continue;
            }
            Object value = attrs.get(name);
            if(value != null){
                result.computeIfAbsent(value.toString(), key -> new ArrayList<>()).add(each);
            }
        }
        return result;
    }

    /**
     * 获取属性矩阵表头
     * @param classInfo 分类
     * @param rowAttrDef 横向展示属性
     * @param colAttrDef 纵向展示属性
     * @return 表头
     */
    private List<EamCiTableVo> getAttrMatrixTableHeader(ESCIClassInfo classInfo, ESCIAttrDefInfo rowAttrDef, ESCIAttrDefInfo colAttrDef) {
        List<EamCiTableVo> result = new ArrayList<>();
        String rowAttrName = rowAttrDef.getProName() + ",[" + classInfo.getClassName() + "]";
        EamCiTableVo rowHeader = new EamCiTableVo(rowAttrDef.getProStdName(), rowAttrName, classInfo.getId(), classInfo.getClassName(), true);
        String colAttrName = colAttrDef.getProName() + ",[" + classInfo.getClassName() + "]";
        EamCiTableVo colHeader = new EamCiTableVo(colAttrDef.getProStdName(), colAttrName, classInfo.getId(), classInfo.getClassName(), true);
        result.add(rowHeader);
        result.add(colHeader);
        for (ESCIAttrDefInfo attrDef : classInfo.getAttrDefs()) {
            //取出label字段
            if(attrDef.getIsCiDisp().equals(1)){
                String attrName = attrDef.getProName() + ",[" + classInfo.getClassName() + "]";
                result.add(new EamCiTableVo(attrDef.getProStdName(), attrName, classInfo.getId(), classInfo.getClassName(), false));
            }
        }
        return result;
    }

    @Override
    public ResponseEntity<byte[]> export(Long id) {
        List<EamMatrixTableVo> matrixTable = this.getMatrixTable(id);
        if(CollectionUtils.isEmpty(matrixTable)){
            throw new ServiceException("没有可导出的数据");
        }
        AppSquareConfig configInfo = configSvc.getInfoById(id);
        //创建一个工作簿
        Workbook workbook = this.writeMatrixToExcel(matrixTable);
        String fileName = configInfo.getCardName().replaceAll("/", "")+ CommUtil.EXCEL07_XLSX_EXTENSION;
        File file = ExcelUtil.writeExcel(workbook, fileName);
        return ExcelUtil.returnRes(file);
    }

    /**
     * 将矩阵表格数据写入工作簿
     * @param matrixTable 矩阵数据
     * @return 工作簿
     */
    private Workbook writeMatrixToExcel(List<EamMatrixTableVo> matrixTable){
        Workbook workbook = new SXSSFWorkbook(new XSSFWorkbook());
        //创建一个新的sheet页
        Sheet sheet = workbook.createSheet("Sheet1");
        AtomicInteger colNum = new AtomicInteger(0);
        for (EamCiTableVo header : matrixTable.get(0).getHeaders()) {
            sheet.setColumnWidth(colNum.incrementAndGet(), 40 * 256);
        }
        // 在第一行第一个单元格中写入数据，并应用合并单元格样式
        AtomicInteger rowNum = new AtomicInteger(0);
        CellStyle titleStyle = ExcelUtil.getTitleStyle(workbook);
        CellStyle headerStyle = ExcelUtil.getHeaderStyle(workbook);
        List<CellRangeAddress> rangeList = new ArrayList<>();
        for (EamMatrixTableVo table : matrixTable) {
            //1.标题行
            rangeList.add(new CellRangeAddress(rowNum.get(), rowNum.get(), 0, table.getHeaders().size()));
            Row titleRow = sheet.createRow(rowNum.getAndIncrement());
            String title = table.getClassName() + "【" + table.getLabel() + "】相关信息表";
            ExcelUtil.createCell(titleRow, titleStyle, title, 0);
            //2.表头行
            Row headerRow = sheet.createRow(rowNum.getAndIncrement());
            AtomicInteger headerColNum = new AtomicInteger(0);
            //插入一列序号
            ExcelUtil.createCell(headerRow, headerStyle, STR_NUM, headerColNum.getAndIncrement());
            for (EamCiTableVo header : table.getHeaders()) {
                String value = header.getProName()+"【" + header.getClassName() + "】";
                ExcelUtil.createCell(headerRow, headerStyle, value, headerColNum.getAndIncrement());
            }
            //3.数据行
            AtomicInteger dataRowNum = new AtomicInteger(0);
            for (Map<String, Object> dataMap : table.getData()) {
                AtomicInteger dataColNum = new AtomicInteger(0);
                Row dataRow = sheet.createRow(rowNum.getAndIncrement());
                //序号列
                ExcelUtil.createCell(dataRow, null, String.valueOf(dataRowNum.incrementAndGet()), dataColNum.getAndIncrement());
                //数据列
                for (EamCiTableVo header : table.getHeaders()) {
                    Object value = dataMap.get(header.getAttrKey());
                    String str = value == null ? "" : value.toString();
                    Cell cell = ExcelUtil.createCell(dataRow, null, str, dataColNum.getAndIncrement());
                    //合并列
                    if(BinaryUtils.isEmpty(str) || !header.getMerge()){
                        continue;
                    }
                    AtomicInteger count = table.getCountMap().remove(str);
                    if(count == null || count.get() == 1){
                        continue;
                    }
                    rangeList.add(new CellRangeAddress(dataRow.getRowNum(), dataRow.getRowNum() + count.get()-1, cell.getColumnIndex(), cell.getColumnIndex()));
                }
            }
            //4.空一行
            Row blankRow = sheet.createRow(rowNum.getAndIncrement());
            rangeList.add(new CellRangeAddress(blankRow.getRowNum(), blankRow.getRowNum(), 0, table.getHeaders().size()));
        }
        rangeList.forEach(sheet::addMergedRegion);
        return workbook;
    }
}
